<?php

namespace api\modules\app\traits;

use api\modules\app\models\Event;
use api\modules\app\models\EventFilterOuter;
use api\modules\app\models\EventStatus;
use api\modules\app\models\OrderStep;
use api\modules\manage\services\MenuService;
use api\utils\StringUtil;

trait QueryTrait
{
    public function getSupportFilter()
    {
        return  [
            'status' => [
                'tableKey' => 'status', 'table' => EventStatus::tableName(), 'matchType' => 'precise', 'type' => 'string',
            ],
            'mixed' => [
                'tableKey' => ['event_id', 'code'], 'table' => Event::tableName(), 'matchType' => 'fuzzy', 'type' => 'string',
                'mixed' => true, // 多 key 模糊查询
            ],
            'eventId' => [
                'tableKey' => 'event_id', 'display' => 'eventId', 'table' => EventFilterOuter::tableName(), 'matchType' => 'fuzzy', 'type' => 'string'
            ],
            'code' => [
                'tableKey' => 'code', 'display' => '案件编号', 'table' => [EventFilterOuter::tableName(), Event::tableName()], 'matchType' => 'fuzzy', 'type' => 'string', 'mixed' => true,
            ],
            'address' => [
                'tableKey' => 'address', 'display' => '发生地址', 'table' => Event::tableName(), 'matchType' => 'fuzzy', 'type' => 'string'
            ],
            'eventTypes' => [
                'tableKey' => ['event_type1', 'event_type2', 'event_type3', 'event_type4'],
                'display' => '案件分类', 'table' => Event::tableName(), 'matchType' => 'precise', 'type' => 'string'
            ],
            'submitType' => [
                'tableKey' => 'submit_type', 'display' => '上报方式', 'table' => Event::tableName(), 'matchType' => 'precise', 'type' => 'integer'
            ],
            'source' => [
                'tableKey' => 'source', 'display' => '案件来源', 'table' => Event::tableName(), 'matchType' => 'precise', 'type' => 'integer'
            ],
            'eventTime' => [
                'tableKey' => 'event_time', 'display' => '上报时间', 'table' => Event::tableName(), 'matchType' => 'range', 'type' => 'datetime'
            ],
            'cuser' => [
                'tableKey' => 'discover_user', 'display' => '上报人', 'table' => Event::tableName(), 'matchType' => 'precise', 'type' => 'string', 'hidden' => true,
            ],
            'dispatching' => [
                'tableKey' => 'dispatching', 'display' => '流转中', 'table' => EventFilterOuter::tableName(), 'matchType' => 'precise', 'type' => 'string', 'hidden' => true,
            ],
            'coopId' => [
                'tableKey' => 'coop_id', 'display' => '协办id', 'table' => EventFilterOuter::tableName(), 'matchType' => 'precise', 'type' => 'string', 'hidden' => true,
            ],
            'meta_level1' => [
                'tableKey' => 'meta_level1', 'display' => '一级', 'table' => EventStatus::tableName(), 'matchType' => 'precise', 'type' => 'integer', 'hidden' => true,
            ],
            'meta_level2' => [
                'tableKey' => 'meta_level2', 'display' => '一级', 'table' => EventStatus::tableName(), 'matchType' => 'precise', 'type' => 'integer', 'hidden' => true,
            ],
            'meta_level3' => [
                'tableKey' => 'meta_level3', 'display' => '一级', 'table' => EventStatus::tableName(), 'matchType' => 'precise', 'type' => 'integer', 'hidden' => true,
            ],
            'meta_level4' => [
                'tableKey' => 'meta_level4', 'display' => '一级', 'table' => EventStatus::tableName(), 'matchType' => 'precise', 'type' => 'integer', 'hidden' => true,
            ],
            'meta_level5' => [
                'tableKey' => 'meta_level5', 'display' => '一级', 'table' => EventStatus::tableName(), 'matchType' => 'precise', 'type' => 'integer', 'hidden' => true,
            ],
            'department' => [
                'tableKey' => 'department', 'display' => '一级', 'table' => EventStatus::tableName(), 'matchType' => 'precise', 'type' => 'integer', 'hidden' => true,
            ],
            'user_id' => [
                'tableKey' => 'user_id', 'display' => '一级', 'table' => EventStatus::tableName(), 'matchType' => 'precise', 'type' => 'integer', 'hidden' => true,
            ],
            'route' => [
                'tableKey' => 'route', 'display' => '流转', 'table' => EventFilterOuter::tableName(), 'matchType' => 'precise', 'type' => 'string', 'hidden' => true,
            ],
            'tags' => [
                'tableKey' => 'tags', 'display' => '流转', 'table' => Event::tableName(), 'matchType' => 'precise', 'type' => 'string',
            ],
            'meta_id' => [
                'tableKey' => 'meta_id', 'display' => '当前所在', 'table' => EventFilterOuter::tableName(), 'matchType' => 'precise', 'type' => 'string', 'hidden' => true,
            ],
        ];
    }

    public function genCondition($params, $dataSource = 'mysql')
    {
        $conditions = [];
        $supportKeys = $this->getSupportFilter();
        foreach ($params as $key => $value) {
            $keys = explode(' ', $key);
            $opt = 'and';
            if (count($keys) > 1) {
                $opt = $keys[0];
                $key = $keys[1];
            }
            $keyConfig = $supportKeys[$key] ?? [];
            if (empty($keyConfig)) {
                // LogUtil::warn(['message' => '未配置的查询条件', 'key' => $key, 'value' => $value]);
                continue;
            }
            if (isset($keyConfig['formater'])) {
                $value = $keyConfig['formater']($value);
            }
            $func = 'format' . ucfirst($dataSource) . ucfirst($keyConfig['type']) . 'Condition';
            if (!method_exists($this, $func)) {
                $func = 'format' . ucfirst($dataSource) . 'StringCondition';
            }
            $condition = $this->$func($value, $keyConfig, $opt);
            if ($dataSource == 'mysql' && !empty($condition)) {
                $conditions = array_merge($conditions, $condition);
            } else {
                !empty($condition['filter']) &&
                        $conditions['bool']['filter'] = array_merge(($conditions['bool']['filter'] ?? []), $condition['filter']);
                !empty($condition['mustShould']) &&
                        $conditions['bool']['must']['bool']['should'] = array_merge(($conditions['bool']['must']['bool']['should'] ?? []), $condition['mustShould']);
                !empty($condition['must_not']) &&
                    $conditions['bool']['must_not'] = array_merge(($conditions['bool']['must_not'] ?? []), $condition['must_not']);
            }
        }

        return $conditions;
    }

    private function formatMysqlStringCondition($value, $config)
    {
        $tableKeys = $config['tableKey'];
        if (is_string($config['tableKey'])) {
            $tableKeys = [$config['tableKey']];
        }
        $values = $value;
        if (!is_array($value)) {
            $values = explode(',', $value);
        }
        $or = ['or'];
        if (is_string($config['table'])) {
            $tables = [$config['table']];
        } else {
            $tables = $config['table'];
        }
        foreach ($tables as $table) {
            foreach ($tableKeys as $index => $key) {
                $value = $values[$index];
                if (StringUtil::isEmpty($value)) { // 多个 key 对应一个 value
                    if (!$config['mixed']) {
                        continue;
                    }
                    $value = $values[0];
                }
                $queryKey = empty($table) ? $key : $table . '.' . $key;
                if ($config['matchType'] == 'fuzzy') {
                    $formatedQuery = ['like', $queryKey, $value];
                } else {
                    if (count($tableKeys) > 1 || count($values) == 1) {
                        // eventTypes => 1,2,3,4
                        $formatedQuery = [$queryKey => $value];
                    } else { // source => [1,2]
                        $formatedQuery = [$queryKey => $values];
                    }
                }
                if ($config['mixed']) {
                    $or[] = $formatedQuery;
                } else {
                    $condition[] = $formatedQuery;
                }
            }
        }

        if ($config['mixed']) {
            $condition[] = $or;
        }

        return $condition;
    }

    private function formatEsStringCondition($value, $config, $opt)
    {
        $tableKeys = $config['tableKey'];
        if (is_string($config['tableKey'])) {
            $tableKeys = [$config['tableKey']];
        }
        $values = $value;
        if (!is_array($value)) {
            $values = explode(',', $value);
        }
        $should = [];
        $filter = [];
        $mustNot = [];
        if (is_string($config['table'])) {
            $tables = [$config['table']];
        } else {
            $tables = $config['table'];
        }
        foreach ($tables as $table) {
            foreach ($tableKeys as $index => $key) {
                $key = $table . '.' . $key;
                $value = $values[$index];
                if (StringUtil::isEmpty($value)) { // 多个 key 对应一个 value
                    if (!$config['mixed']) {
                        continue;
                    }
                    $value = $values[0];
                }

                if ($config['matchType'] == 'fuzzy') {
                    $value = '*' . $value . '*';
                    $formatedQuery = ['wildcard' => [$key => $value]];
                } else {
                    if (count($tableKeys) > 1 || count($values) == 1) {
                        $formatedQuery = ['term' => [$key => $values[$index]]];
                    } else {
                        $formatedQuery = ['terms' => [$key => $values]];
                    }
                }
                if ($config['mixed']) {
                    $should[] = $formatedQuery;
                } elseif ($opt == 'not') {
                    $mustNot[] = $formatedQuery;
                } else {
                    $filter[] = $formatedQuery;
                }
            }
        }
        if (!empty($should)) {
            $bool['mustShould'] = $should;
        }
        if (!empty($filter)) {
            $bool['filter'] = $filter;
        }
        if (!empty($mustNot)) {
            $bool['must_not'] = $mustNot;
        }

        return $bool ?? [];
    }

    private function formatMysqlDatetimeCondition($value, $config)
    {
        $queryKey = empty($config['table']) ? $config['tableKey'] : $config['table'] . '.' . $config['tableKey'];
        $condition[] = ['between', $queryKey, date('Y-m-d H:i:s', $value[0]), date('Y-m-d H:i:s', $value[1])];

        return $condition;
    }

    private function formatEsDatetimeCondition($value, $config)
    {
        $filter[] = [
            'range' => [
                $config['table'] . '.' . $config['tableKey'] => [
                    'gte' => $value[0],
                    'lte' => $value[1],
                ],
            ],
        ];

        return ['filter' => $filter];
    }

    public function genOrderBy($params, $dataSource = 'mysql')
    {
        $sortKey = $params['sort'] ?? 'event_time';
        $sqlSortType = empty($params['sort_type']) ? SORT_DESC: SORT_ASC;
        $esSortType = empty($params['sort_type']) ? 'desc': 'asc';
        switch ($sortKey) {
            case 'status_time':
                $foramtSortKey = EventFilterOuter::tableName() . '.status_time';
                break;
            case 'step_time':
                $foramtSortKey = OrderStep::tableName() . '.created_at';
                break;
            case 'all_deadline':
            case 'deal_deadline':
                // TODO 改成通用 deadline 根据 status + deadline 区分
            default:
                $foramtSortKey = Event::tableName() . '.event_time';
                break;
        }

        if ($dataSource == 'mysql') {
            return [$foramtSortKey => $sqlSortType];
        }

        return [$foramtSortKey => ['order' => $esSortType]];
    }

    /**
     * @return [
     *      'offset' => 10 * 1,
     *      'limit' => 10
     * ]
     */
    public function genPagination($params)
    {
        return [
            'offset' => $params['per-page'] * ($params['page'] - 1),
            'limit' => $params['per-page'],
        ];
    }
}
